/*
 * My_Spi_NoCS.c
 *
 * - 软件主机 SPI 位操作（MSB-first），不使用 CS
 * - 帧协议：0xAA 作为帧头，结束标志为 aabbccddeeffeeddccbbaa
 * - 收到帧头后进入阻塞接收，检测到完整结束标志时退出阻塞
 * - 保留500ms超时作为异常保护，校验响应格式与TCP对齐（1字节类型+4字节序号）
 */

#include "My_Spi.h"
#include "My_InFlash.h"
#include "crc32_table.h"
#include <string.h>
#include <stdio.h>
#include "main.h"  // 用于 HAL_GetTick()
#include <stdint.h>

// DWT 延迟初始化（用于SPI时序）
static void DWT_Delay_Init(void) {
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

static inline void delay_us(uint32_t us) {
    uint32_t start = DWT->CYCCNT;
    uint32_t cycles = us * (SystemCoreClock / 1000000UL);
    while ((DWT->CYCCNT - start) < cycles) { __NOP(); }
}

// -------------------------- 帧协议常量 --------------------------
#define SPI_SOF        0xAA  // 帧起始标志
const uint8_t SPI_EOF[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA};
#define SPI_EOF_LEN    11    // 结束标志长度
#define RX_TIMEOUT_MS  500   // 异常超时保护

// 响应类型（与TCP对齐）
#define RESP_ACK       0x00  // 校验成功
#define RESP_NACK      0x01  // 校验失败

// -------------------------- SPI 接收状态结构 --------------------------
typedef enum
{
    SPI_STAGE_WAIT_HEADER,
    SPI_STAGE_WAIT_BLOCK,
    SPI_STAGE_FINISH
} SpiTransferStage;

typedef struct
{
    SpiTransferStage stage;
    uint8_t recv_buf[8192 + 24]; // 接收缓冲
    uint32_t recv_len;           // 当前接收长度
    uint8_t in_blocking;         // 阻塞接收标志
    uint32_t last_recv_time;     // 最后接收时间
    uint8_t eof_match_count;     // EOF匹配计数

    // 文件传输参数
    uint32_t total_file_size;
    uint32_t total_blocks;
    uint32_t block_size;
    uint32_t global_crc32;
    uint32_t current_block_idx;
    uint32_t accumulated_crc32;
} SpiRecvState;

static SpiRecvState spi_state;

static update_callback_SPI_t update_Complete_callback = NULL; //升级完成回调
void set_update_Spi_complete_callback(update_callback_SPI_t callback) {
    update_Complete_callback = callback;
}

static update_callback_SPI_t update_Begin_callback = NULL; //升级开始回调
void set_update_Spi_Begin_callback(update_callback_SPI_t callback) {
    update_Begin_callback = callback;
}

static update_callback_SPI_t update_Block_callback = NULL; //升级块回调
void set_update_Spi_Block_callback(update_callback_SPI_t callback) {
    update_Block_callback = callback;
}
// 外部函数声明
extern uint16_t crc16_xmodem(const uint8_t* data, uint32_t len);
extern uint32_t crc32_incremental(const uint8_t* data, uint32_t len, uint32_t prev_crc);

// -------------------------- 工具：小端读取（与TCP对齐） --------------------------
static inline uint32_t read_u32_le(const uint8_t* p) {
    return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
}

static inline uint16_t read_u16_le(const uint8_t* p) {
    return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
}

// -------------------------- 逐位全双工收发 --------------------------
uint8_t My_Spi_Transceive_Byte(uint8_t txDat) {
    uint8_t rxDat = 0;
    for (uint8_t i = 0; i < 8; i++) {
        SPI_MOSI((txDat & (0x80 >> i)) ? 1 : 0);
        delay_us(100);
        SPI_SCL(1);
        delay_us(100);
        SPI_SCL(0);
        delay_us(100);
        rxDat = (rxDat << 1) | (SPI_MISO ? 1 : 0);

    }
    return rxDat;
}
// -------------------------- 发送SPI响应（带帧头和结束标志，与数据帧格式对齐） --------------------------
static void spi_send_response(uint8_t resp_type, uint32_t block_idx) {
    // 响应数据本体（5字节：1字节类型+4字节块序号，小端）
    uint8_t resp_data[5] = {
        resp_type,
        (uint8_t)(block_idx & 0xFF),
        (uint8_t)((block_idx >> 8) & 0xFF),
        (uint8_t)((block_idx >> 16) & 0xFF),
        (uint8_t)((block_idx >> 24) & 0xFF)
    };

    // 1. 发送帧头（0xAA，与数据帧一致）
    My_Spi_Transceive_Byte(SPI_SOF);
    // 2. 发送响应数据本体（5字节）
    for (uint8_t i = 0; i < 5; i++) {
        My_Spi_Transceive_Byte(resp_data[i]);
    }
    // 3. 发送结束标志（aabbccddeeffeeddccbbaa，11字节）
    for (uint8_t i = 0; i < SPI_EOF_LEN; i++) {
        My_Spi_Transceive_Byte(SPI_EOF[i]);
    }

}
// -------------------------- 数据解析函数（带规范响应） --------------------------
static void spi_parse_data() {
    if (spi_state.recv_len == 0)
        return;

    // 有效数据长度（剔除EOF）
    uint32_t valid_len = spi_state.recv_len;
    if (valid_len == 0) {
        printf("无有效数据\r\n");
        return;
    }

    uint8_t valid_buf[8192 + 24];
    memcpy(valid_buf, spi_state.recv_buf, valid_len);
    uint32_t temp_recv_len = valid_len;

    while (1) {
        if (spi_state.stage == SPI_STAGE_WAIT_HEADER) {
            if (temp_recv_len < 20)
                break;

            uint32_t magic = read_u32_le(valid_buf);
            if (magic != 0x55AA55AAU) {
                printf("文件头错误：魔数=0x%08X\r\n", magic);
                // 发送文件头错误的NACK（块序号填0xFFFFFFFF）
                spi_send_response(RESP_NACK, 0xFFFFFFFF);
                temp_recv_len = 0;
                break;
            }

            // 解析文件头参数
            spi_state.total_file_size = read_u32_le(valid_buf + 4);
            spi_state.total_blocks = read_u32_le(valid_buf + 8);
            spi_state.block_size = read_u32_le(valid_buf + 12);
            spi_state.global_crc32 = read_u32_le(valid_buf + 16);
            spi_state.accumulated_crc32 = 0;

            printf("文件头解析成功：总大小=%u, 总块=%u, 块大小=%u, 全局CRC=0x%08X\r\n",
                   spi_state.total_file_size, spi_state.total_blocks, spi_state.block_size, spi_state.global_crc32);
            if (update_Begin_callback) {
                update_Begin_callback(1);
            }
            if (InternalFlash_Erase(APP2, 256 * 1024, 2)) {
                printf("擦除失败\r\n");
            }

            // 切换到块接收状态
            spi_state.stage = SPI_STAGE_WAIT_BLOCK;
            spi_state.current_block_idx = 0;

            // 移动剩余数据
            uint32_t remain = temp_recv_len - 20;
            if (remain > 0)
                memmove(valid_buf, valid_buf + 20, remain);
            temp_recv_len = remain;
            continue;
        } else if (spi_state.stage == SPI_STAGE_WAIT_BLOCK) {
            if (temp_recv_len < 6)
                break;

            uint32_t block_idx = read_u32_le(valid_buf);
            uint16_t data_len = read_u16_le(valid_buf + 4);
            uint32_t total_block_len = 6 + data_len + 2;

            if (temp_recv_len < total_block_len)
                break;

            // 校验块CRC
            uint8_t* block_data = valid_buf + 6;
            uint16_t recv_crc16 = read_u16_le(valid_buf + 6 + data_len);
            uint16_t calc_crc16 = crc16_xmodem(block_data, data_len);

            uint8_t resp_type = RESP_NACK; // 默认NACK
            if (block_idx == spi_state.current_block_idx && calc_crc16 == recv_crc16) {
                resp_type = RESP_ACK; // ACK
                printf("块%u校验成功 长度=%u CRC=0x%04X\r\n",
                       (unsigned)block_idx, data_len, calc_crc16);
                // 更新全局CRC32
                spi_state.accumulated_crc32 = crc32_incremental(block_data, data_len, spi_state.accumulated_crc32);
                if (update_Block_callback) {
                    update_Block_callback(1);
                }

                // 写入Flash
                if (InFlash_Write(APP2 + (block_idx * spi_state.block_size), block_data, data_len) != 0) {
                    printf("块%u写入Flash失败！\r\n", (unsigned)block_idx);
                    resp_type = RESP_NACK;
                } else {
                    spi_state.current_block_idx++;
                }
            } else {
                if (block_idx != spi_state.current_block_idx)
                    printf("块序号错: 收到%u 预期%u\r\n", (unsigned)block_idx, (unsigned)spi_state.current_block_idx);
                else
                    printf("块%u CRC错: 收到0x%04X 计算0x%04X\r\n",
                           (unsigned)block_idx, recv_crc16, calc_crc16);
            }

            // 发送块校验响应（与TCP格式一致）
            spi_send_response(resp_type, block_idx);

            // 移动剩余数据
            uint32_t remain = temp_recv_len - total_block_len;
            if (remain > 0)
                memmove(valid_buf, valid_buf + total_block_len, remain);
            temp_recv_len = remain;

            // 检查是否完成所有块
            if (spi_state.current_block_idx >= spi_state.total_blocks) {
                printf("所有块接收完成，开始全局校验\r\n");
                spi_state.stage = SPI_STAGE_FINISH;
                uint8_t final_result = (spi_state.accumulated_crc32 == spi_state.global_crc32) ? RESP_ACK : RESP_NACK;
                printf("全局CRC：本地0x%08X vs 预期0x%08X -> %s\r\n",
                       spi_state.accumulated_crc32, spi_state.global_crc32,
                       final_result == RESP_ACK ? "成功" : "失败");
                // 调用回调函数通知上层
                if (update_Complete_callback) {
                    update_Complete_callback(final_result);
                }

                // 发送全局校验结果（块序号填0xFFFFFFFE表示最终结果）
                spi_send_response(final_result, 0xFFFFFFFE);
            }
            continue;
        } else {
            break;
        }
    }
}

// -------------------------- 字节处理函数 --------------------------
static void spi_process_byte(uint8_t byte) {
    // 检测帧头（非阻塞状态）
    if (byte == SPI_SOF && spi_state.in_blocking == 0) {
        spi_state.recv_len = 0;
        spi_state.in_blocking = 1;
        spi_state.last_recv_time = HAL_GetTick();
        spi_state.eof_match_count = 0;
        printf("检测到帧头（0xAA），进入阻塞接收模式\r\n");
        return;
    }

    // 阻塞模式下处理数据并检测EOF
    if (spi_state.in_blocking) {
        if (byte == SPI_EOF[spi_state.eof_match_count]) {
            spi_state.eof_match_count++;
            if (spi_state.eof_match_count >= SPI_EOF_LEN) {
                printf("检测到完整结束标志，退出阻塞接收\r\n");
                spi_state.in_blocking = 0;
                return;
            }
        } else {
            if (spi_state.eof_match_count > 0) {
                for (uint8_t i = 0; i < spi_state.eof_match_count; i++) {
                    if (spi_state.recv_len < sizeof(spi_state.recv_buf)) {
                        spi_state.recv_buf[spi_state.recv_len++] = SPI_EOF[i];
                    } else {
                        printf("缓冲溢出，强制退出\r\n");
                        spi_state.in_blocking = 0;
                        spi_state.recv_len = 0;
                        spi_state.eof_match_count = 0;
                        return;
                    }
                }
                spi_state.eof_match_count = 0;
            }
        }

        if (spi_state.eof_match_count == 0) {
            if (spi_state.recv_len < sizeof(spi_state.recv_buf)) {
                spi_state.recv_buf[spi_state.recv_len++] = byte;
                spi_state.last_recv_time = HAL_GetTick();
            } else {
                printf("缓冲溢出，强制退出\r\n");
                spi_state.in_blocking = 0;
                spi_state.recv_len = 0;
                spi_state.eof_match_count = 0;
            }
        }
    }
}

// -------------------------- 初始化 --------------------------
void My_Spi_Init(void) {
    DWT_Delay_Init();
    memset(&spi_state, 0, sizeof(SpiRecvState));
    spi_state.stage = SPI_STAGE_WAIT_HEADER;
    spi_state.in_blocking = 0;
    spi_state.eof_match_count = 0;
    printf("SPI主机初始化完成（响应格式与TCP对齐）\r\n");
}

// -------------------------- 主循环逻辑 --------------------------
void Updata_loop(void) {
    // 非阻塞状态：检测帧头
    if (!spi_state.in_blocking) {
        uint8_t rx_byte = My_Spi_Transceive_Byte(0x00);
        if (rx_byte == SPI_SOF) {
            spi_process_byte(rx_byte);
        }
        return;
    }

    // 阻塞接收：直到EOF或超时
    while (spi_state.in_blocking) {
        uint8_t rx_byte = My_Spi_Transceive_Byte(0x00);
        spi_process_byte(rx_byte);

        // 超时保护
        uint32_t current_time = HAL_GetTick();
        uint32_t time_diff = (current_time >= spi_state.last_recv_time)
                                 ? (current_time - spi_state.last_recv_time)
                                 : (0xFFFFFFFF - spi_state.last_recv_time + current_time);

        if (time_diff > RX_TIMEOUT_MS) {
            spi_state.in_blocking = 0;
            printf("异常超时，共接收%u字节\r\n", spi_state.recv_len);

        }
    }

    // 解析数据
    spi_parse_data();
    // 重置状态
    spi_state.recv_len = 0;
    spi_state.eof_match_count = 0;
}